#include "StdAfx.h"
#include "NetworkDrive.h"

using namespace Adaptive::Foundation;
using namespace Adaptive::Win32;
using namespace Adaptive::Win32::Network;

typedef int (__cdecl* WNetRestoreConnection)(HMODULE, LPCSTR);

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods

NetworkDrive::NetworkDrive()
{
	_localDriveLetter = DEFAULT_LOCAL;
	_shareName = String::Empty;
}
NetworkDrive::NetworkDrive(String^ localLetter, String^ shareName)
{
	_localDriveLetter = localLetter;
	_shareName = shareName;
}
NetworkDrive::~NetworkDrive()
{
	_shareName = nullptr;
	_localDriveLetter = nullptr;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Properties
 *------------------------------------------------------------------------------*/
#pragma region Public Properties
bool NetworkDrive::ForceConnection::get()
{
	return _forceConnection;
}
void NetworkDrive::ForceConnection::set(bool value)
{
	_forceConnection = value;
}
bool NetworkDrive::PersistentConnection::get()
{
	return _persistent;
}
void NetworkDrive::PersistentConnection::set(bool value)
{
	_persistent = value;
}
bool NetworkDrive::PromptForCredentials::get()
{
	return _promptForCredentials;
}
void NetworkDrive::PromptForCredentials::set(bool value)
{
	_promptForCredentials = value;
}
bool NetworkDrive::SaveCredentials::get()
{
	return _saveCredentials;
}
void NetworkDrive::SaveCredentials::set(bool value)
{
	_saveCredentials = value;
}
String^ NetworkDrive::LocalDriveLetter::get()
{
	return _localDriveLetter;
}
void NetworkDrive::LocalDriveLetter::set(String^ value)
{
	_localDriveLetter = value;
}
String^ NetworkDrive::ShareName::get()
{
	return _shareName;
}
void NetworkDrive::ShareName::set(String^ value)
{
	_shareName = value;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Public Methods / Functions
// Attempts to map the drive using the specified credentials.
void NetworkDrive::MapDrive(String^ userId, String^ password)
{
    NETRESOURCE netResource;							//Network resource structure.
    int flags = 0;                                      //Flags to pass to API call.
    int result = 0;                                     //Result of API call.
	CString wideUserId = userId;
	CString widePwd = password;
	CString localDrive = _localDriveLetter;
	CString wideShare = _shareName;

    //Poppulate structure.
    netResource.dwScope = 2;
    netResource.dwType = RESOURCETYPE_DISK;
    netResource.dwDisplayType = 3;
    netResource.dwUsage = 1;
    netResource.lpRemoteName = localDrive.GetBuffer();
    netResource.lpLocalName = wideShare.GetBuffer();

    //Set flags.
    if (_saveCredentials)
        flags += CONNECT_CMD_SAVECRED;

    if (_persistent)
        flags += CONNECT_UPDATE_PROFILE;

    if (_promptForCredentials)
        flags += CONNECT_INTERACTIVE + CONNECT_PROMPT;

    //When forcing, unmap the drive first to force a re-connection.
    if (_forceConnection)
        UnMapDrive(true);
    
    //Execute API call.
	if ((userId->Length == 0) || (password->Length == 0))
		result = WNetAddConnection2(&netResource, NULL, NULL, flags);
	else
		result = WNetAddConnection2(&netResource, widePwd, wideUserId, flags);

    if (result > 0)
		throw gcnew System::ComponentModel::Win32Exception(result); 

}
// Unmaps the network drive.
void NetworkDrive::UnMapDrive(bool force)
{
	CString localDrive = _localDriveLetter;
	CString wideShare = _shareName;
    int flags = 0;                      //Execution flags.
    int result = 0;                     //API call result.

    //Set flags.
    if (_persistent)
        flags += CONNECT_UPDATE_PROFILE;

    //Try the drive letter first.
    result = WNetCancelConnection2(localDrive, flags, (int)(force));

    if (result != 0)
        //Try by the network share name.
        result = WNetCancelConnection2(wideShare, flags, (int)(force));

    if (result > 0)
		throw gcnew System::ComponentModel::Win32Exception(result);
}
// <summary>
// Attempts to restore a network connection.
// </summary>
void NetworkDrive::RestoreDrive()
{
    int result = 0;
	HMODULE libraryHandle = NULL;
	WNetRestoreConnection functionPtr = NULL;

	libraryHandle = ::LoadLibrary(L"mpr.dll");
	if (libraryHandle != NULL)
	{
		functionPtr = (WNetRestoreConnection)::GetProcAddress(libraryHandle, "WNetRestoreConnectionW");
		if (functionPtr != NULL)
			result = (functionPtr)(0, NULL);
		
		FreeLibrary(libraryHandle);
	}
	else
		throw gcnew System::ComponentModel::Win32Exception(GetLastError());
    if (result > 0)
		throw gcnew System::ComponentModel::Win32Exception(result);
}
#pragma endregion
